/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 
 * 系统版本: 1.0.0
 * 开发人员: Frank
 * 开发时间: 2019/8/31 19:22
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.message.common.sender.sms.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.spring.arch.message.common.sender.sms.SmsResult;
import com.spring.arch.message.common.sender.sms.SmsSender;
import com.spring.arch.message.common.sender.sms.SmsResult;
import com.spring.arch.message.common.sender.sms.SmsSender;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 阿里云短信发送
 * @author Frank
 * @version 1.0.0.1
 * @since 2019/8/31 19:22
 */
@Slf4j
public class AliSmsSender extends SmsSender {

    private final boolean enabled;
    private final String signName;
    private final String accessKeyId;
    private final String accessKeySecret;

    /**
     * 响应状态码
     */
    private static Map<String, String> statusMap = new HashMap<>();
    static {
        statusMap.put("OK", "请求成功");
        statusMap.put("isp.RAM_PERMISSION_DENY", "RAM权限DENY");
        statusMap.put("isv.OUT_OF_SERVICE", "业务停机");
        statusMap.put("isv.PRODUCT_UN_SUBSCRIPT", "未开通云通信产品的阿里云客户");
        statusMap.put("isv.PRODUCT_UNSUBSCRIBE", "产品未开通");
        statusMap.put("isv.ACCOUNT_NOT_EXISTS", "账户不存在");
        statusMap.put("isv.ACCOUNT_ABNORMAL", "账户异常");
        statusMap.put("isv.SMS_TEMPLATE_ILLEGAL", "短信模板不合法");
        statusMap.put("isv.SMS_SIGNATURE_ILLEGAL", "短信签名不合法");
        statusMap.put("isv.INVALID_PARAMETERS", "参数异常");
        statusMap.put("isp.SYSTEM_ERROR", "ISP系统错误");
        statusMap.put("isv.MOBILE_NUMBER_ILLEGAL", "非法手机号");
        statusMap.put("isv.MOBILE_COUNT_OVER_LIMIT", "手机号码数量超过限制");
        statusMap.put("isv.TEMPLATE_MISSING_PARAMETERS", "模板缺少变量");
        statusMap.put("isv.BUSINESS_LIMIT_CONTROL", "业务限流");
        statusMap.put("isv.INVALID_JSON_PARAM", "JSON参数不合法，只接受字符串值");
        statusMap.put("isv.BLACK_KEY_CONTROL_LIMIT", "黑名单管控");
        statusMap.put("isv.PARAM_LENGTH_LIMIT", "参数超出长度限制");
        statusMap.put("isv.PARAM_NOT_SUPPORT_URL", "不支持URL");
        statusMap.put("isv.AMOUNT_NOT_ENOUGH", "账户余额不足");
    }

    /**
     * 产品名称:云通信短信API产品,开发者无需替换 阿里云短信测试专用
     */
    private static final String PRODUCT = "Dysmsapi";

    /**
     * 产品域名,开发者无需替换
     */
    private static final String API = "dysmsapi.aliyuncs.com";

    private static final String SUCCESS = "OK";

    public AliSmsSender(boolean enabled, String signName, String accessKeyId, String accessKeySecret) {
        this.enabled = enabled;
        this.signName = signName;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
    }

    @Override
    public SmsResult sendSms(String templateCode, String params, String phoneNumber) {
        if (enabled) {
            return doSendSms(templateCode, params, phoneNumber);
        }
        log.info("短信功能未开启，phoneNumber：{} params：{}", phoneNumber, params);
        return SmsResult.failure("短信功能未开启");
    }

    /**
     * Send sms send sms response.
     * <p>
     * 阿里云短信
     *
     * @param templateCode the template code
     * @param params       the params
     * @param phoneNumber  the phone number
     * @return the send sms response
     */
    private SmsResult doSendSms(String templateCode, String params, String phoneNumber) {
        try {
            // 初始化客户端
            IAcsClient acsClient = initClient();
            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers(phoneNumber);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(signName);
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(templateCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            log.debug("短信参数:{}", params);

            // 参数json
            request.setTemplateParam(params);
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            String status = sendSmsResponse.getCode();
            String msg = "{\"状态码\":\"%s\",\"描述\":\"%s\"}";
            msg = String.format(msg, status, statusMap.get(status));
            log.debug("发送结果：{}", msg);
            if (SUCCESS.equals(status)) {
                return SmsResult.success(sendSmsResponse);
            }
            return SmsResult.failure(msg);
        } catch (Exception e) {
            log.error("发送异常 {}", params, e);
            return SmsResult.failure(e.getMessage());
        }
    }

    /**
     * 查询发送详情
     * @param phoneNum 手机号
     * @param bizId    业务编号
     * @param sendDate 发送时间
     */
    public QuerySendDetailsResponse querySendDetails(String phoneNum, String bizId, String sendDate) throws ClientException {
        // 初始化客户端
        IAcsClient acsClient = initClient();
        QuerySendDetailsRequest request = new QuerySendDetailsRequest();
        request.setPhoneNumber(phoneNum);
        request.setBizId(bizId);
        request.setSendDate(sendDate);
        // 分页查询
        request.setPageSize(10L);
        request.setCurrentPage(1L);
        return acsClient.getAcsResponse(request);
    }

    /**
     * 初始化客户端
     */
    private IAcsClient initClient() {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "5000");
        System.setProperty("sun.net.client.defaultReadTimeout", "5000");
        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-hangzhou", PRODUCT, API);
        return new DefaultAcsClient(profile);
    }


}
